import math
from threading import Thread
from decimal import Decimal
T = Decimal(1e-3)
G = Decimal(1e5)
#G = Decimal(1)

class V2D(tuple): #vector 2D
    def __init__(self,v) -> None:
        self.x = Decimal(v[0])
        self.y = Decimal(v[1])

    def __add__(self,other): # +
        return V2D((self.x+other.x, self.y+other.y))

    def __sub__(self,other): # -
        return V2D((self.x-other.x, self.y-other.y))
    
    def __mul__(self,other): # num *
        if isinstance(other,V2D):
            return V2D((self.x*other.x, self.y*other.y))
        elif isinstance(other,Decimal):
            return V2D((self.x*other, self.y*other))

    def __truediv__(self,other): # /
        if isinstance(other,V2D):
            return V2D((self.x/other.x, self.y/other.y))
        elif isinstance(other,Decimal):
            return V2D((self.x/other, self.y/other))

    def __pow__(self,other): # dot *
        return self.x*other.x+self.y*other.y

    def get_val(self): #returm tuple
        return self.x, self.y

    def dist2(a,b): #return dist^2
        if b == 0:
            r = a*a
            return r[0]+r[1]
        else:
            return V2D.dist2(a-b,0)
    
    def get_arg(self):
        pass
        #arg = Decimal.atan(self.y/self.x)
        
class MP(): #Mass Point
    def __init__(self,init,F=None) -> None:
        self.m = Decimal(init[0])
        self.x = V2D(init[1])
        self.v = V2D(init[2])
        self.a = V2D((0,0))

    def step(self,F): #Newton 2 Law
        self.a = F/self.m
        self.x += self.v*T
        self.v += self.a*T

    def pos(self):
        return self.x.get_val()
    
    def dist2(self,other):
        return self.x.dist(other.x)

class Field():
    pass

class World():
    def step(self):
        self.time+=T
        F = [V2D((0,0)) for i in range(self.mp_num)]
        for i in range(self.mp_num):
            for j in range(i+1,self.mp_num):
                xi = self.MPs[i].x
                xj = self.MPs[j].x
                r = xi-xj
                dist2 = xi.dist2(xj)
                dist = Decimal.sqrt(dist2)
                cos, sin = r/dist
                mi = self.MPs[i].m
                mj = self.MPs[j].m
                f_ij = G*mi*mj/dist2
                F_vec = V2D((f_ij*cos,f_ij*sin))
                F[i] -= F_vec
                F[j] += F_vec
        for i in range(self.mp_num):
            self.MPs[i].step(F[i])
    
    def __get_pos(self):
        pos = []
        for i in range(self.mp_num):
            pos.append(self.MPs[i].pos())
        self.pos = pos

    def flash(self):
        while(self.flag):
            self.step()
            self.__get_pos()
    
    def run(self):
        self.flag = True
        self.thread.start()
    
    def stop(self):
        self.flag = False

    def __init__(self,init) -> None:
        self.time = Decimal(0)
        self.MPs = []
        for i in init:
            self.MPs.append(MP(i))
        self.mp_num = len(self.MPs)
        self.pos = []
        self.__get_pos()
        self.flag = False
        self.thread = Thread(None,self.flash)